package com.sscl.baselibrary.popupwindow

import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.annotation.IdRes
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.viewbinding.ViewBinding
import com.sscl.baselibrary.exts.getParameterizedType
import com.sscl.baselibrary.exts.saveAs
import com.sscl.baselibrary.exts.saveAsUnChecked
import com.sscl.baselibrary.utils.BaseManager
import java.lang.reflect.ParameterizedType

/**
 * 自定义PopupWindow基类
 *
 * @author pengh
 */
abstract class BaseViewBindingPopupWindow<VB : ViewBinding> @JvmOverloads constructor(
    protected val context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
    defStyleRes: Int = 0,
    width: Int =  ViewGroup.LayoutParams.MATCH_PARENT,
    height: Int =  ViewGroup.LayoutParams.MATCH_PARENT,
    focusable: Boolean = true
) : PopupWindow(
    context, attrs, defStyleAttr, defStyleRes
), LifecycleOwner {

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 属性声明
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /* * * * * * * * * * * * * * * * * * * 私有常量属性 * * * * * * * * * * * * * * * * * * */

    @Suppress("LeakingThis")
    private val lifecycleRegistry = LifecycleRegistry(this)



    /* * * * * * * * * * * * * * * * * * * 延时初始化属性 * * * * * * * * * * * * * * * * * * */

    protected val mBinding: VB

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 构造方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    init {
        val type = getParameterizedType()
        val vbClass: Class<VB> = type.saveAs<ParameterizedType>().actualTypeArguments[0].saveAs()
        val method = vbClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
        mBinding = method.invoke(this, LayoutInflater.from(context))!!.saveAsUnChecked()
        contentView = mBinding.root
        this.width = width
        this.height = height
        isFocusable = focusable
        BaseManager.handler.post {
            doBeforeInitOthers()
            initViews()
            initViewData()
            initOtherData()
            initEvents()
            doAfterAll()
        }
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 实现方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    override val lifecycle: Lifecycle
        get() = lifecycleRegistry


    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 抽象方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 在初始化其他数据之前执行的操作
     */
    protected abstract fun doBeforeInitOthers()

    /**
     * 初始化控件
     */
    protected abstract fun initViews()

    /**
     * 初始化控件的数据
     */
    protected abstract fun initViewData()

    /**
     * 初始化其他数据
     */
    protected abstract fun initOtherData()

    /**
     * 初始化事件
     */
    protected abstract fun initEvents()

    /**
     * 在最后执行的操纵
     */
    protected abstract fun doAfterAll()

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 重写方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    override fun showAtLocation(parent: View?, gravity: Int, x: Int, y: Int) {
        super.showAtLocation(parent, gravity, x, y)
        lifecycleRegistry.currentState = Lifecycle.State.CREATED
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    }

    override fun dismiss() {
        super.dismiss()
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
        lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
    }

    override fun showAsDropDown(anchor: View?, xoff: Int, yoff: Int, gravity: Int) {
        super.showAsDropDown(anchor, xoff, yoff, gravity)
        lifecycleRegistry.currentState = Lifecycle.State.CREATED
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * protected方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 让PopupWindow可以和Activity一样拥有findViewById方法
     *
     * @param viewId 控件id
     * @return 控件
     */
    protected fun <T : View> findViewById(@IdRes viewId: Int): T {
        val contentView: View? = contentView
        if (contentView != null) {
            return contentView.findViewById(viewId)
        }
        throw NullPointerException("contentView is null")
    }

    /**
     * 显示popup window
     *
     * @param parent  父布局
     * @param gravity Gravity
     * @param x       x坐标
     * @param y       y坐标
     */
    @JvmOverloads
    fun show(parent: View, gravity: Int = Gravity.CENTER, x: Int = 0, y: Int = 0) {
        showAtLocation(parent, gravity, x, y)
    }
}